// 版权所有2012 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 此文件定义操作数和相关操作。

package types2

import (
	"bytes"
	"cmd/compile/internal/syntax"
	"fmt"
	"go/constant"
	"go/token"
)

// 操作数模式指定操作数的（寻址）模式。
type operandMode byte

const (
	invalid   operandMode = iota // 操作数无效
	novalue                      // 操作数表示没有值（函数调用的结果，没有结果）
	builtin                      // 操作数是内置函数
	typexpr                      // 操作数是类型
	constant_                    // 操作数是常量；操作数的类型是基本类型
	variable                     // 操作数是可寻址变量
	mapindex                     // 操作数是映射索引表达式（在赋值的lhs上充当变量，在rhs上充当commaok）
	value                        // 操作数是计算值
	nilvalue                     // 操作数是零值
	commaok                      // 类似值，但操作数可以用逗号，ok表达式
	commaerr                     // 与commaok类似，但第二个值是error，而不是布尔值
	cgofunc                      // 操作数是cgo函数
)

var operandModeString = [...]string{
	invalid:   "invalid operand",
	novalue:   "no value",
	builtin:   "built-in",
	typexpr:   "type",
	constant_: "constant",
	variable:  "variable",
	mapindex:  "map index expression",
	value:     "value",
	nilvalue:  "nil",
	commaok:   "comma, ok expression",
	commaerr:  "comma, error expression",
	cgofunc:   "cgo function",
}

// 操作数表示类型检查期间的中间值。
// 操作数具有（寻址）模式，表达式计算为
// 操作数、操作数的类型、常量的值以及内置函数的id 
// 。
// 操作数的零值是一个随时可用的无效操作数。
// 
type operand struct {
	mode operandMode
	expr syntax.Expr
	typ  Type
	val  constant.Value
	id   builtinId
}

// Pos返回与x对应的表达式的位置。
// 如果x无效，则该位置为nopos。
// 
func (x *operand) Pos() syntax.Pos {
	// x无效时不能设置x.expr 
	if x.expr == nil {
		return nopos
	}
	return x.expr.Pos()
}

// 操作数字符串格式
// （由于类型系统的原因，并非所有“非类型化”的情况都会出现，但在这里它们会自然消失）
// 
// 模式格式
// 
// 无效<expr>（<mode>）
// novalue<expr>（<mode>）
// builtin<expr>（<mode>）
// typexpr<expr>（<mode>）
// 
// constant<expr>（<untyped kind><mode>）
// constant<expr>（<typ>类型的<mode>）
// constant<expr>（<untyped kind><mode><val>）
// constant<expr>（<typ>类型的<mode><val>）
// 
// variable<expr>（<untyped kind><mode>）
// 
// mapindex<expr>（<untyped kind><mode>）
// mapindex<expr>（<mode>类型<typ>）
// 
// value<expr>（<untyped kind kind><mode>）
// value<expr>（<mode>类型<typ>）
// 
// nilvalue非类型的nil 
// nilvalue nil（类型<typ>）
// 
// commaok<expr>（<untyped kind><mode>）
// commaok<expr>（<mode type>类型的<mode>）
// 
// commaerr<expr>（<mode>类型<typ>）
// 
// cgofunc<expr>（<untyped kind><mode>）
// 
func operandString(x *operand, qf Qualifier) string {
	// 
	if x.mode == nilvalue {
		switch x.typ {
		case nil, Typ[Invalid]:
			return "nil (with invalid type)"
		case Typ[UntypedNil]:
			return "nil"
		default:
			return fmt.Sprintf("nil (of type %s)", TypeString(x.typ, qf))
		}
	}

	var buf bytes.Buffer

	var expr string
	if x.expr != nil {
		expr = syntax.String(x.expr)
	} else {
		switch x.mode {
		case builtin:
			expr = predeclaredFuncs[x.id].name
		case typexpr:
			expr = TypeString(x.typ, qf)
		case constant_:
			expr = x.val.String()
		}
	}

	// /<expr>（
	if expr != "" {
		buf.WriteString(expr)
		buf.WriteString(" (")
	}

	// /<untyped kind>
	hasType := false
	switch x.mode {
	case invalid, novalue, builtin, typexpr:
		// 没有类型
	default:
		// 应该有一个类型，但要小心（打印时不要崩溃）
		if x.typ != nil {
			if isUntyped(x.typ) {
				buf.WriteString(x.typ.(*Basic).name)
				buf.WriteByte(' ')
				break
			}
			hasType = true
		}
	}

	// /<mode>
	buf.WriteString(operandModeString[x.mode])

	if x.mode == constant_ {
		if s := x.val.String(); s != expr {
			buf.WriteByte(' ')
			buf.WriteString(s)
		}
	}

	if hasType {
		if x.typ != Typ[Invalid] {
			var intro string
			if isGeneric(x.typ) {
				intro = " of parameterized type "
			} else {
				intro = " of type "
			}
			buf.WriteString(intro)
			WriteType(&buf, x.typ, qf)
			if tpar, _ := x.typ.(*TypeParam); tpar != nil {
				buf.WriteString(" constrained by ")
			}
		} else {
			buf.WriteString(" with invalid type")
		}
	}

	// /）
	if expr != "" {
		buf.WriteByte(')')
	}

	return buf.String()
}

func (x *operand) String() string {
	return operandString(x, nil)
}

func (x *operand) setConst(k syntax.LitKind, lit string) {
	var kind BasicKind
	switch k {
	case syntax.IntLit:
		kind = UntypedInt
	case syntax.FloatLit:
		kind = UntypedFloat
	case syntax.ImagLit:
		kind = UntypedComplex
	case syntax.RuneLit:
		kind = UntypedRune
	case syntax.StringLit:
		kind = UntypedString
	default:
		unreachable()
	}

	val := constant.MakeFromLiteral(lit, kind2tok[k], 0)
	if val.Kind() == constant.Unknown {
		x.mode = invalid
		x.typ = Typ[Invalid]
		return
	}
	x.mode = constant_
	x.typ = Typ[kind]
	x.val = val
}

// isNil报告x是类型化的还是非类型化的nil值。
func (x *operand) isNil() bool { return x.mode == nilvalue }

// assignableTo报告x是否可分配给T类型的变量。如果
// 结果为假，并且提供了非零原因，则可能会将其设置为更
// 故障的详细解释（结果！=“”）。返回的错误代码
// 仅在（第一个）结果为false时有效。如果通过导出的API调用调用assignableTo，即当所有
// 。
// 方法都已进行类型检查时，则check参数可能为nil 
func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, errorCode) {
	if x.mode == invalid || T == Typ[Invalid] {
		return true, 0 // 避免错误
	}

	V := x.typ

	// x的类型与T 
	if Identical(V, T) {
		return true, 0
	}

	Vu := under(V)
	Tu := under(T)
	Vp, _ := V.(*TypeParam)
	Tp, _ := T.(*TypeParam)

	// x是一个可由T类型的值表示的非类型化值。
	if isUntyped(Vu) {
		assert(Vp == nil)
		if Tp != nil {
			// T是一个类型参数：如果它是
			// 可由T类型集中的每个特定类型表示，则x可分配给T。
			return Tp.is(func(t *term) bool {
				if t == nil {
					return false
				}
				// 一个术语可以是一个波浪术语，但非类型化值的基础
				// 类型不可分配改变，所以我们不需要做任何特别的事情。
				newType, _, _ := check.implicitTypeAndValue(x, t.typ)
				return newType != nil
			}), _IncompatibleAssign
		}
		newType, _, _ := check.implicitTypeAndValue(x, T)
		return newType != nil, _IncompatibleAssign
	}
	// Vu的类型为

	// x的类型V和T具有相同的基础类型
	// 并且V或T中至少有一个不是命名类型
	// 并且V和T都不是类型参数。
	if Identical(Vu, Tu) && (!hasName(V) || !hasName(T)) && Vp == nil && Tp == nil {
		return true, 0
	}

	// T是接口类型，x实现T，T不是类型参数。
	// 也处理T是指向接口的指针的情况。
	if _, ok := Tu.(*Interface); ok && Tp == nil || isInterfacePtr(Tu) {
		if err := check.implements(V, T); err != nil {
			if reason != nil {
				*reason = err.Error()
			}
			return false, _InvalidIfaceAssign
		}
		return true, 0
	}

	// 如果V是接口，请检查是否存在缺少类型断言的问题。
	if Vi, _ := Vu.(*Interface); Vi != nil && Vp == nil {
		if check.implements(T, V) == nil {
			// T实现了V，所以给出关于类型断言的提示。
			if reason != nil {
				*reason = "need type assertion"
			}
			return false, _IncompatibleAssign
		}
	}

	// x是双向通道值，T是通道
	// 类型，x的类型V和T具有相同的元素类型，
	// 并且V或T中至少有一个不是命名类型。
	if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
		if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) {
			return !hasName(V) || !hasName(T), _InvalidChanAssign
		}
	}

	// 优化：如果我们没有类型参数，我们就完成了
	if Vp == nil && Tp == nil {
		return false, _IncompatibleAssign
	}

	errorf := func(format string, args ...interface{}) {
		if check != nil && reason != nil {
			msg := check.sprintf(format, args...)
			if *reason != "" {
				msg += "\n\t" + *reason
			}
			*reason = msg
		}
	}

	// x的类型V不是命名类型，t是类型参数，
	// x可分配给t的类型集中的每个特定类型。
	if !hasName(V) && Tp != nil {
		ok := false
		code := _IncompatibleAssign
		Tp.is(func(T *term) bool {
			if T == nil {
				return false // 没有特定类型
			}
			ok, code = x.assignableTo(check, T.typ, reason)
			if !ok {
				errorf("cannot assign %s to %s (in %s)", x.typ, T.typ, Tp)
				return false
			}
			return true
		})
		return ok, code
	}

	// x的类型V是一个类型参数，T不是一个命名类型，
	// 和V的类型集中每个特定类型的值x'是
	// 可分配给T的。
	if Vp != nil && !hasName(T) {
		x := *x // 不要敲击外部x 
		ok := false
		code := _IncompatibleAssign
		Vp.is(func(V *term) bool {
			if V == nil {
				return false // 没有特定类型
			}
			x.typ = V.typ
			ok, code = x.assignableTo(check, T, reason)
			if !ok {
				errorf("cannot assign %s (in %s) to %s", V.typ, Vp, T)
				return false
			}
			return true
		})
		return ok, code
	}

	return false, _IncompatibleAssign
}

// kind2tok翻译语法。这是一种代币。代币。
var kind2tok = [...]token.Token{
	syntax.IntLit:    token.INT,
	syntax.FloatLit:  token.FLOAT,
	syntax.ImagLit:   token.IMAG,
	syntax.RuneLit:   token.CHAR,
	syntax.StringLit: token.STRING,
}
